﻿/*
* Copyright (c) 2010-2012 Tesla Engine Group
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/


using System;
using Tesla.Input;
using Tesla.Windows.Util;

namespace Tesla.Windows.Input {
    /// <summary>
    /// Wrapper for a windows mouse.
    /// </summary>
    public class WindowsMouseWrapper : IMouseWrapper {
        private IntPtr _handle;
        private MouseHook _hook = new MouseHook();

        /// <summary>
        /// Gets or sets the window handle the mouse is bound to. Mouse screen coordinates
        /// are relative to the top-left corner of this window.
        /// </summary>
        public IntPtr Handle {
            get {
                return _handle;
            }
            set {
                _handle = value;
            }
        }

        /// <summary>
        /// Get the current mouse state.
        /// </summary>
        /// <returns>MouseState struct</returns>
        public MouseState GetMouseState() {
            Point pt;
            NativeMethods.GetCursorPos(out pt);
            if(_handle != IntPtr.Zero) {
                NativeMethods.ScreenToClient(_handle, ref pt);
            }
            ButtonState lButton = (ButtonState) (((ushort) NativeMethods.GetAsyncKeyState(1)) >> 15);
            ButtonState rButton = (ButtonState) (((ushort) NativeMethods.GetAsyncKeyState(2)) >> 15);
            ButtonState mButton = (ButtonState) (((ushort) NativeMethods.GetAsyncKeyState(4)) >> 15);
            ButtonState xButton1 = (ButtonState) (((ushort) NativeMethods.GetAsyncKeyState(5)) >> 15);
            ButtonState xButton2 = (ButtonState) (((ushort) NativeMethods.GetAsyncKeyState(6)) >> 15);
            int wheel = MouseHook.CurrentWheel;

            return new MouseState(pt.X, pt.Y, wheel, lButton, rButton, mButton, xButton1, xButton2);
        }

        /// <summary>
        /// Get the current mouse state.
        /// </summary>
        /// <param name="handle">Handle to a window</param>
        /// <returns>MouseState struct</returns>
        public MouseState GetMouseState(IntPtr handle) {
            Point pt;
            NativeMethods.GetCursorPos(out pt);
            if(handle != IntPtr.Zero) {
                NativeMethods.ScreenToClient(handle, ref pt);
            }
            ButtonState lButton = (ButtonState) (((ushort) NativeMethods.GetAsyncKeyState(1)) >> 15);
            ButtonState rButton = (ButtonState) (((ushort) NativeMethods.GetAsyncKeyState(2)) >> 15);
            ButtonState mButton = (ButtonState) (((ushort) NativeMethods.GetAsyncKeyState(4)) >> 15);
            ButtonState xButton1 = (ButtonState) (((ushort) NativeMethods.GetAsyncKeyState(5)) >> 15);
            ButtonState xButton2 = (ButtonState) (((ushort) NativeMethods.GetAsyncKeyState(6)) >> 15);
            int wheel = MouseHook.CurrentWheel;

            return new MouseState(pt.X, pt.Y, wheel, lButton, rButton, mButton, xButton1, xButton2);
        }

        /// <summary>
        /// Set the mouse position.
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        public void SetPosition(int x, int y) {
            Point pt;
            pt.X = x;
            pt.Y = y;
            if(_handle != IntPtr.Zero) {
                NativeMethods.ClientToScreen(_handle, ref pt);
                NativeMethods.SetCursorPos(pt.X, pt.Y);
            }
        }

    }
}
